package com.huaxin.hxmodulesystem.common;

import com.huaxin.hxmodulesystem.dto.response.CaptchaResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Base64;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.UUID;

@Component
public class CaptchaUtil {

    @Autowired
    private StringRedisTemplate redisTemplate;

    // 验证码过期时间（秒）
    private static final long EXPIRE_SECONDS = 300; // 5分钟

    // 验证码字符集
    private static final String CHAR_SET = "0123456789";
    private static final int WIDTH = 120;
    private static final int HEIGHT = 40;
    private static final int LENGTH = 4;

    /**
     * 生成验证码并返回包含 Base64 图片和 key 的结果
     */
    public CaptchaResult generateCaptcha() {
        String code = generateTextCode();
        BufferedImage image = createImage(code);

        String imageBase64 = toBase64(image);
        String key = UUID.randomUUID().toString();

        // 存入 Redis，5分钟后过期
        redisTemplate.opsForValue().set("captcha:" + key, code, EXPIRE_SECONDS, TimeUnit.SECONDS);

        return new CaptchaResult(key, imageBase64);
    }

    /**
     * 校验验证码（登录时调用）
     *
     * @param key       生成时返回的 key
     * @param userInput 用户输入的验证码
     * @return 是否正确
     */
    public boolean validateCaptcha(String key, String userInput) {
        String redisKey = "captcha:" + key;
        String savedCode = redisTemplate.opsForValue().get(redisKey);

        if (savedCode != null && savedCode.equalsIgnoreCase(userInput)) {
            // 校验成功，删除验证码（防止重放）
            redisTemplate.delete(redisKey);
            return true;
        }
        return false;
    }

    /**
     * 生成随机验证码文本
     */
    private String generateTextCode() {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < LENGTH; i++) {
            sb.append(CHAR_SET.charAt(random.nextInt(CHAR_SET.length())));
        }
        return sb.toString();
    }

    /**
     * 创建带干扰的验证码图片
     */
    private BufferedImage createImage(String code) {
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();

        // 背景色
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, WIDTH, HEIGHT);

        // 字体
        g.setFont(new Font("Arial", Font.BOLD | Font.ITALIC, 24));
        Color[] color = {Color.RED, Color.GREEN, Color.BLUE, Color.DARK_GRAY, Color.BLACK};
        Random random = new Random();

        // 绘制字符
        for (int i = 0; i < code.length(); i++) {
            g.setColor(color[random.nextInt(color.length)]);
            g.drawString(String.valueOf(code.charAt(i)), 23 * i + 10, 25);
        }

        // 干扰线
        for (int i = 0; i < 5; i++) {
            g.setColor(getRandColor(100, 200));
            int x1 = random.nextInt(WIDTH);
            int y1 = random.nextInt(HEIGHT);
            int x2 = random.nextInt(WIDTH);
            int y2 = random.nextInt(HEIGHT);
            g.drawLine(x1, y1, x2, y2);
        }

        // 噪点
        for (int i = 0; i < 30; i++) {
            int x = random.nextInt(WIDTH);
            int y = random.nextInt(HEIGHT);
            g.setColor(getRandColor(150, 250));
            g.drawOval(x, y, 1, 1);
        }

        g.dispose();
        return image;
    }

    /**
     * 转换为 Base64 字符串
     */
    private String toBase64(BufferedImage image) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            ImageIO.write(image, "jpg", baos);
            byte[] imageBytes = baos.toByteArray();
            return Base64.getEncoder().encodeToString(imageBytes);
        } catch (Exception e) {
            throw new RuntimeException("图像编码失败", e);
        }
    }

    /**
     * 生成随机颜色
     */
    private Color getRandColor(int fc, int bc) {
        Random random = new Random();
        if (fc > 255) fc = 255;
        if (bc > 255) bc = 255;
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }

}